﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;

using Roslyn.Compilers;
using Roslyn.Compilers.CSharp;

using RexToy;
using RexToy.Xml;

namespace ScriptXCompiler
{
    class Program
    {
        private static string _csprojFile;
        private static string _outputDir;
        private static string _config;
        private static string _suppressWarnings = string.Empty;
        private static bool _singleFile = true;
        private static bool _writeFile = true;
        private static bool _jsonNameQuote = false;

        private static bool ExtractParams(string[] args)
        {
            foreach (var arg in args)
            {
                var idx = arg.IndexOf(":");
                if (idx < 0)
                {
                    return false;
                }
                string p = arg.Substring(0, idx);
                if (p == "p" || p == "-p")
                {
                    _csprojFile = arg.Substring(idx + 1);
                    continue;
                }
                if (p == "o" || p == "-o")
                {
                    _outputDir = arg.Substring(idx + 1);
                    continue;
                }
                if (p == "s" || p == "-s")
                {
                    _singleFile = bool.Parse(arg.Substring(idx + 1));
                    continue;
                }
                if (p == "w" || p == "-w")
                {
                    _writeFile = bool.Parse(arg.Substring(idx + 1));
                    continue;
                }
                if (p == "c" || p == "-c")
                {
                    _config = arg.Substring(idx + 1);
                    continue;
                }
                if (p == "q" || p == "-q")
                {
                    _jsonNameQuote = bool.Parse(arg.Substring(idx + 1));
                    continue;
                }
                if (p == "i" || p == "-i")
                {
                    _suppressWarnings = arg.Substring(idx + 1);
                    continue;
                }
                return false;
            }
            if (string.IsNullOrEmpty(_csprojFile))
                return false;
            if (string.IsNullOrEmpty(_outputDir))
                return false;
            if (!File.Exists(_csprojFile))
            {
                Console.WriteLine("Project file not exist.");
                return false;
            }

            return true;
        }

        private static void ShowMessage()
        {
            Console.WriteLine("C# Cross Compiler, version [{0}]", GetVersion());
            Console.WriteLine("Usage: ScriptXCompile -o:<output dir> -p:<csproj file> [-c:<Debug|Release>] [-s:<true|false>] [-w:<true|false>] [-q:<true|false>]");
            Console.WriteLine("     s: single file[default is true]");
            Console.WriteLine("     q: add quote to name in json string[default is false]");
            Console.WriteLine("     w: write to file(true write to false[which is default], false write to console).");
            Console.WriteLine("         No effect when integrate as MSBuild, always write to file.");
            Console.WriteLine("         Mainly use for debug purpose in command line mode.");
            Console.WriteLine("     i: supress CSXC warning #.");
            Console.WriteLine("     c: Debug or Release. In release mode, use YUI(.NET) to compress.");
            Console.WriteLine("         No effect when use command line. always output read-able code.");
            Console.WriteLine(@"    Example: p:..\..\Sample\Sample.csproj o:..\..\Sample\bin\Debug");
            Console.WriteLine(@"Recommend usage, in VS project post-build event:");
            Console.WriteLine(@"    [Path]ScriptXCompile -o:$(TargetDir) -p:$(ProjectDir)$(ProjectFileName) -s:false -i:1029,1030");
        }

        static void Main(string[] args)
        {
            GetVersion();
            if (!ExtractParams(args))
            {
                ShowMessage();
            }
            else
            {
                CompileEngine engine = new CompileEngine();
                engine.InitializeCompiler(_csprojFile, _outputDir, "Debug", _singleFile, _writeFile, _jsonNameQuote, _suppressWarnings);

                ErrorAggregator aggregator = engine.Compile();

                OutputCompileInfo(aggregator);
            }
            Console.ReadLine();
        }

        public static string GetVersion()
        {
            var assembly = System.Reflection.Assembly.GetExecutingAssembly();
            string[] strArr = assembly.FullName.Split(',', StringSplitOptions.RemoveEmptyEntries);
            foreach (var str in strArr)
            {
                var pair = str.Split('=');
                if (pair.Length == 2 && pair[0].Trim() == "Version")
                    return pair[1].Trim();
            }
            return string.Empty;
        }

        private static void OutputCompileInfo(ErrorAggregator aggregator)
        {
            if (!aggregator.HasError)
            {
                ConsoleColorController.SetForeGroundColour(ConsoleColor.Green);
                Console.WriteLine("++++++++++ Compile by CSXC(C# Cross Compiler) {0} Success. ++++++++++", GetVersion());
                ConsoleColorController.SetForeGroundColour();
            }
            else
            {
                ConsoleColorController.SetForeGroundColour(ConsoleColor.Red);
                Console.WriteLine("++++++++++ Compile by CSXC(C# Cross Compiler) {0} have error(s). ++++++++++", GetVersion());
                ConsoleColorController.SetForeGroundColour();
            }

            var count = 1;
            foreach (CompileIssue issue in aggregator.Issues)
            {
                switch (issue.IssueType)
                {
                    case IssueType.Error:
                        ConsoleColorController.SetForeGroundColour(ConsoleColor.Red, true);
                        break;

                    case IssueType.Warning:
                        ConsoleColorController.SetForeGroundColour(ConsoleColor.Yellow, true);
                        break;

                    default:
                        ConsoleColorController.SetForeGroundColour(ConsoleColor.Blue, true);
                        break;
                }

                Console.WriteLine("[{0}]:[CSXC-{1}:{2}]->{3}", count.ToString("000"), issue.IssueId.ToString("0000"), issue.IssueType, issue.Message);
                Console.WriteLine("\tat {0}", issue.Location.ToString());

                count++;
            }
        }
    }
}
